/******************************************************************************
 * FileName:    gwin_global_data.c
 * Desc:        全局变量
 *
 *
 * Author:      Lin
 * Notes:
 *
 ******************************************************************************/

/*-------------------------- Includes ---------------------------------------*/
#include "gwin_global_data.h"
#include "gwin_protocol_task.h"

#include "gwin_miot_security.h"


/*-------------------------- Macro Definitions ------------------------------*/
#define LOCAL_DEBUG_EN                      ( 1 )
#if LOCAL_DEBUG_EN
#define GWIN_DEBUG(...)                     USER_DEBUG(__VA_ARGS__)
#else
#define GWIN_DEBUG(...)
#endif


/*-------------------------- Type Declarations ------------------------------*/

/*-------------------------- Global Variables -------------------------------*/
/**
 * @brief 系统参数
 */
extern system_param_t system_param;


/**
 * @brief 系统默认参数
 */
static const system_param_product_t defualt_product =
{
    .model = GWIN_PRODUCT_MODEL,
    .pid = GWIN_PRODUCT_PID,
    .version = _TO_STR(GWIN_PRODUCT_APP_DEVELOPER_VERSION),
    .version_num = _GWIN_PRODUCT_APP_DEVELOPER_VERSION,
    .miot_security_siid = GWIN_MIOT_SECURITY_SIID,
    .network_timeout = 30 * 60 * 1000,
};
static const uint32_t defualt_network_provisioned = 0;


/**
 * @brief 参数表
 */
static const system_param_default_t system_param_default_map[] =
{
    [RECORD_ID_PRODUCT_CFG] =           { sizeof(system_param.product),             (uint8_t*)(&system_param.product),                                      (uint8_t*)(&defualt_product),                       },
    [RECORD_ID_NETWORK] =               { sizeof(system_param.network_provisioned), (uint8_t*)(&system_param.network_provisioned),                          (uint8_t*)(&defualt_network_provisioned),           },
    [RECORD_ID_SPEC] =                  { sizeof(system_param.spec) / 2,            (uint8_t*)(&system_param.spec),                                         NULL,                                               },
    [RECORD_ID_SPEC_2] =                { sizeof(system_param.spec) / 2,            (uint8_t*)(&system_param.spec) + sizeof(system_param.spec) / 2,         NULL,                                               },
    [RECORD_ID_SPEC_STR] =              { sizeof(system_param.spec_str) / 2,        (uint8_t*)(&system_param.spec_str),                                     NULL,                                               },
    [RECORD_ID_SPEC_STR_2] =            { sizeof(system_param.spec_str) / 2,        (uint8_t*)(&system_param.spec_str) + sizeof(system_param.spec_str) / 2, NULL,                                               },
};
static const uint8_t system_param_default_map_cnt = sizeof(system_param_default_map) / sizeof(system_param_default_map[0]);


static const record_id_t record_id_check_map[] =
{
    RECORD_ID_SPEC,
    RECORD_ID_SPEC_2,
    RECORD_ID_SPEC_STR,
    RECORD_ID_SPEC_STR_2,
};
static const uint8_t record_id_check_map_cnt = sizeof(record_id_check_map) / sizeof(record_id_check_map[0]);

/*-------------------------- Local Variables --------------------------------*/

/*-------------------------- Functions Declarations -------------------------*/
static uint8_t _gwin_custom_record_id_check(uint16_t record_id);
static void gwin_custom_system_param_init(void);
static uint8_t gwin_custom_record_check_product_mark(void);
static void gwin_custom_record_reset_product_mark(void);


/*-------------------------- Functions Definitions --------------------------*/
/**
 * @brief 用户存储区 检查
 *          最多创建 16 条记录，总数据长度不超过 512 字节，写入数据， 数据长度需要 4 字节对齐
 */
void gwin_custom_record_check(void)
{
    uint16_t record_len_sum = 0;

    if (system_param_default_map_cnt > 16)
    {
        // 最多创建 16 条记录
        GWIN_DEBUG("Error : custom record count over 16!!!");
        while(1);
    }

    for (uint8_t i = 0; i < system_param_default_map_cnt; i++)
    {
        if (system_param_default_map[i].size % 4 != 0)
        {
            // 数据长度需要 4 字节对齐
            GWIN_DEBUG("Error : custom record id[%d] size[%d] not align at 4 byte!!!", i, system_param_default_map[i].size);
            while(1);
        }
        GWIN_DEBUG("Error : custom record id[%d] size[%d] not align at 4 byte!!!", i, system_param_default_map[i].size);

        if(_gwin_custom_record_id_check(i) == 0)                // PaulLin 2025年5月21日: 因为目前MCU上报的条数过多,已经不够存入到FLASH中,所以就不能存入到FLASH中,放在RAM中使用,掉电不保存
        {
            continue;
        }
        record_len_sum += system_param_default_map[i].size;
        if (record_len_sum > 512)
        {
            // 总数据长度不超过 512 字节
            GWIN_DEBUG("Error : custom record over 512 byte!!!");
            while(1);
        }
    }
}

/**
 * @brief 检查record id 是否有效
 * @param record_id 记录ID
 * @return 1 有效 0 无效
 * @note 因为某些record id 已经不够存储参数了,所以就不能存入到flash中，所以需要检查record id 是否有效
 */
static uint8_t _gwin_custom_record_id_check(uint16_t record_id)
{
    for(uint8_t i = 0; i < record_id_check_map_cnt; i++)
    {
        if(record_id == record_id_check_map[i])
        {
            return 0;
        }
    }

    return 1;
}

/**
 * @brief 用户存储区 读取
 */
void gwin_custom_record_load(void)
{
    gwin_custom_record_check();

    memset(&system_param, 0x00, sizeof(system_param_t));

    if (gwin_custom_record_check_product_mark())
    {
        system_param.reset_all_force = 1;
    }
    else
    {
        for (uint8_t i = RECORD_ID_MIN; i < system_param_default_map_cnt; i++)
        {
            if(_gwin_custom_record_id_check(i) == 0)                // PaulLin 2025年5月21日: 因为目前MCU上报的条数过多,已经不够存入到FLASH中,所以就不能存入到FLASH中,放在RAM中使用,掉电不保存
            {
                continue;
            }
            if (MI_SUCCESS != miio_record_read(i, system_param_default_map[i].memory_addr, system_param_default_map[i].size))
            {
                GWIN_DEBUG("Load Failed : id[%d] size[%d]", i, system_param_default_map[i].size);
                gwin_custom_record_reset(i);
            }
        }
    }

    gwin_custom_system_param_init();
}

/**
 * @brief 用户存储区 保存
 */
void gwin_custom_record_save(uint16_t record_id)
{
    if(_gwin_custom_record_id_check(record_id) == 0)                // PaulLin 2025年5月21日: 因为目前MCU上报的条数过多,已经不够存入到FLASH中,所以就不能存入到FLASH中,放在RAM中使用,掉电不保存
    {
        return;
    }
    miio_record_write(record_id, system_param_default_map[record_id].memory_addr, system_param_default_map[record_id].size);
    if (record_id == RECORD_ID_SPEC)
    {
        gwin_custom_record_save(RECORD_ID_SPEC_2);
    }
}

/**
 * @brief 用户存储区 重置
 */
void gwin_custom_record_reset(uint16_t record_id)
{
    if(_gwin_custom_record_id_check(record_id) == 0)                // PaulLin 2025年5月21日: 因为目前MCU上报的条数过多,已经不够存入到FLASH中,所以就不能存入到FLASH中,放在RAM中使用,掉电不保存
    {
        return;
    }
    miio_record_delete(record_id);
    miio_record_create(record_id, system_param_default_map[record_id].size);
    if (system_param_default_map[record_id].defalut_addr != NULL)
    {
        memcpy(system_param_default_map[record_id].memory_addr, system_param_default_map[record_id].defalut_addr, system_param_default_map[record_id].size);
    }
    else
    {
        memset(system_param_default_map[record_id].memory_addr, 0x00, system_param_default_map[record_id].size);
    }
    miio_record_write(record_id, system_param_default_map[record_id].memory_addr, system_param_default_map[record_id].size);
}

/**
 * @brief 用户存储区 重置
 */
void gwin_custom_record_reset_all(void)
{
    static const uint8_t record_id_reserve_map[] = { RECORD_ID_PRODUCT_CFG, RECORD_ID_NETWORK };
    static const uint8_t record_id_reserve_cnt = sizeof(record_id_reserve_map) / sizeof(record_id_reserve_map[0]);

    uint8_t reserve_index = 0;
    for (uint8_t i = RECORD_ID_MIN; i < system_param_default_map_cnt; i++)
    {
        if (reserve_index < record_id_reserve_cnt && i == record_id_reserve_map[reserve_index])
        {
            reserve_index++;
            continue;
        }
        gwin_custom_record_reset(i);
    }
}

/**
 * @brief 用户存储区 检查产品标识符
 *          产品标识符判断，防止烧录不同产品，匹配不对，则强制复位所有参数
 */
static uint8_t gwin_custom_record_check_product_mark(void)
{
    uint8_t reset = 0;

    product_mark_t product_mark;
    memset(&product_mark, 0x00, sizeof(product_mark_t));
    if (MI_SUCCESS != miio_record_read(RECORD_ID_PRODUCT_MARK, (uint8_t *)&product_mark, sizeof(product_mark_t)))
    {
        reset = 1;
    }
    else
    {
        uint8_t len = MAX(strlen((char *)product_mark.model_name), strlen(GWIN_PRODUCT_MARK));
        if (memcmp(product_mark.model_name, GWIN_PRODUCT_MARK, len) != 0)
        {
            reset = 1;
        }
    }
    if (reset)
    {
        #if (!PRODUCT_MARK_NETWORK_RESET_AUTO)
        reset = 0;
        gwin_custom_record_reset_all_force_force();
        #else
        // 还原所有参数
        for (uint8_t i = RECORD_ID_MIN; i < system_param_default_map_cnt; i++)
        {
            if (system_param_default_map[i].defalut_addr != NULL)
            {
                memcpy(system_param_default_map[i].memory_addr, system_param_default_map[i].defalut_addr, system_param_default_map[i].size);
            }
            else
            {
                memset(system_param_default_map[i].memory_addr, 0x00, system_param_default_map[i].size);
            }
        }
        #endif
    }

    return reset;
}

/**
 * @brief 用户存储区 重置 产品标识符
 */
static void gwin_custom_record_reset_product_mark(void)
{
    product_mark_t product_mark;
    memset(&product_mark, 0x00, sizeof(product_mark_t));
    memcpy(product_mark.model_name, GWIN_PRODUCT_MARK, strlen(GWIN_PRODUCT_MARK));

    miio_record_delete(RECORD_ID_PRODUCT_MARK);
    miio_record_create(RECORD_ID_PRODUCT_MARK, sizeof(product_mark_t));
    miio_record_write(RECORD_ID_PRODUCT_MARK, (uint8_t *)&product_mark, sizeof(product_mark_t));
}

/**
 * @brief 用户存储区 重置 强制强制
 *          用于已经烧录不同的产品，必须把整个flash都擦掉，还要等待协议栈初始化以后重置网络
 */
void gwin_custom_record_reset_all_force_force(void)
{
    extern void mible_record_clear(void);
    mible_record_clear();

    extern void user_record_clear(void);
    user_record_clear();

    gwin_custom_record_reset_product_mark();

    // 重置所有参数
    for (uint8_t i = RECORD_ID_MIN; i < system_param_default_map_cnt; i++)
    {
        gwin_custom_record_reset(i);
    }
}

/**
 * @brief 系统参数初始化
 */
static void gwin_custom_system_param_init(void)
{
    if (!system_param.product.version_custom_enable)
    {
        memset(system_param.product.version, 0x00, sizeof(system_param.product.version));
        memcpy(system_param.product.version, _TO_STR(GWIN_PRODUCT_APP_DEVELOPER_VERSION), strlen(_TO_STR(GWIN_PRODUCT_APP_DEVELOPER_VERSION)));
        system_param.product.version_num = _GWIN_PRODUCT_APP_DEVELOPER_VERSION;
    }

    m_config.model = (char *)system_param.product.model;
    m_config.pid = system_param.product.pid;
    #if (GWIN_PRODUCT_VERSION_FIXED_ENABLE)
    m_config.developer_version = _TO_STR(GWIN_PRODUCT_APP_DEVELOPER_VERSION);
    #else
    m_config.developer_version = system_param.product.version;
    #endif

    system_param.timezone = INVALID_I8;
    system_param.weather = INVALID_U16;

    system_param.low_pwr_ctrl_second = LOW_PWR_TIME_SECOND;
    system_param.sys_state_extern = INVALID_U8;
    if (!system_param.network_provisioned)
    {
        system_param.network_timeout = system_param.product.network_timeout / 1000;
    }
}

/**
 * @brief 系统参数初始化 在ble初始化之后
 */
void gwin_custom_system_param_init_after_ble(void)
{
    uint8_t mac_addr[BLE_MAC_ADDR_LEN];
    gap_get_mac(mac_addr);
    for (uint8_t i = 0; i < BLE_MAC_ADDR_LEN; i++)
    {
        system_param.mac_addr[i] = mac_addr[BLE_MAC_ADDR_LEN - 1 - i];
    }

    // 米家照明开关加密算法
    #if GWIN_MIOT_SECURITY_ENABLE
    gwin_miot_security_decrypted_data(mac_addr, &system_param.miot_security[0], &system_param.miot_security[1]);
    if (system_param.spec.len == 0)
    {
        system_param.spec.data[SPEC_INDEX_MIOT_SECURITY_0].change = 1;
        system_param.spec.data[SPEC_INDEX_MIOT_SECURITY_0].siid = system_param.product.miot_security_siid;
        system_param.spec.data[SPEC_INDEX_MIOT_SECURITY_0].piid = 1;
        system_param.spec.data[SPEC_INDEX_MIOT_SECURITY_0].data_type = DATA_TYPE_U32;
        system_param.spec.data[SPEC_INDEX_MIOT_SECURITY_0].value = system_param.miot_security[0];
        system_param.spec.len++;

        system_param.spec.data[SPEC_INDEX_MIOT_SECURITY_1].change = 1;
        system_param.spec.data[SPEC_INDEX_MIOT_SECURITY_1].siid = system_param.product.miot_security_siid;
        system_param.spec.data[SPEC_INDEX_MIOT_SECURITY_1].piid = 2;
        system_param.spec.data[SPEC_INDEX_MIOT_SECURITY_1].data_type = DATA_TYPE_U32;
        system_param.spec.data[SPEC_INDEX_MIOT_SECURITY_1].value = system_param.miot_security[1];
        system_param.spec.len++;

        gwin_custom_record_save(RECORD_ID_SPEC);
    }
    gwin_save_general_clock(&system_param.system_upload_clock[0]);
    gwin_save_general_clock(&system_param.system_upload_clock[1]);
#else
    gwin_miot_security_decrypted_data_1(system_param.mac_addr, &system_param.miot_security[0]);
    if (system_param.spec.len == 0)
    {
        system_param.spec.data[SPEC_INDEX_MIOT_SECURITY_0].change = 1;
        system_param.spec.data[SPEC_INDEX_MIOT_SECURITY_0].siid = system_param.product.miot_security_siid;
        system_param.spec.data[SPEC_INDEX_MIOT_SECURITY_0].piid = 1;
        system_param.spec.data[SPEC_INDEX_MIOT_SECURITY_0].data_type = DATA_TYPE_U32;
        system_param.spec.data[SPEC_INDEX_MIOT_SECURITY_0].value = system_param.miot_security[0];
        system_param.spec.len++;

        gwin_custom_record_save(RECORD_ID_SPEC);
    }
    gwin_save_general_clock(&system_param.system_upload_clock[0]);
#endif
}


/*-------------------------- END OF FILE ------------------------------------*/

